{"componentChunkName":"component---src-templates-blog-post-js","path":"/Today I Learned/mobile_touch_swipe_indicator/","result":{"data":{"site":{"siteMetadata":{"title":"JULog","author":"[Ju Chan Hwang]","siteUrl":"https://julog.netlify.app","comment":{"disqusShortName":"","utterances":"JuChanHwang/gatsby-starter-bee"},"sponsor":{"buyMeACoffeeId":"jbee"}}},"markdownRemark":{"id":"975e7b0a-95d3-507f-8043-4c057ad27b97","excerpt":"ISSUE 캐러셀 UI에서 20개의 item을 보여야함 추가적인 item은 오른쪽 스와이핑 액션을 통해 해당 페이지로 넘어가야함 touchmove(스와이핑)이벤트가 발생해는 x값에 따라 퍼센테이지를 UI로 제공 해결 방안 item의 개수가 20개 이상일 때에만 swipe indicator를 보여주기 위한 filtering을 한다.  event를 감지해서 스크롤이 끝에 도달할 경우 이벤트를 전파한다.  끝에 도달할 경우, touchStartX시점에서 touchmove의 이동량을 계산하여 xDiff…","html":"<h2 id=\"issue\" style=\"position:relative;\"><a href=\"#issue\" aria-label=\"issue permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>ISSUE</h2>\n<ul>\n<li>캐러셀 UI에서 20개의 item을 보여야함</li>\n<li>\n<p>추가적인 item은 오른쪽 스와이핑 액션을 통해 해당 페이지로 넘어가야함</p>\n<img width=\"600\" alt=\"스크린샷 2020-06-27 오후 3 57 51\" src=\"https://user-images.githubusercontent.com/36187948/85916788-f8f69d80-b88e-11ea-92a9-85bde0edb959.png\">\n</li>\n<li>\n<p>touchmove(스와이핑)이벤트가 발생해는 x값에 따라 퍼센테이지를 UI로 제공</p>\n<img width=\"600\" alt=\"스크린샷 2020-06-27 오후 4 01 50\" src=\"https://user-images.githubusercontent.com/36187948/85916862-94880e00-b88f-11ea-9951-fb4734941e4a.png\">\n<img width=\"600\" alt=\"스크린샷 2020-06-27 오후 4 02 01\" src=\"https://user-images.githubusercontent.com/36187948/85916863-9782fe80-b88f-11ea-87bc-b76b043ef0b2.png\">\n<img width=\"600\" alt=\"스크린샷 2020-06-27 오후 4 02 11\" src=\"https://user-images.githubusercontent.com/36187948/85916864-9782fe80-b88f-11ea-8839-8b41a3c16bf9.png\">\n</li>\n</ul>\n<h2 id=\"해결-방안\" style=\"position:relative;\"><a href=\"#%ED%95%B4%EA%B2%B0-%EB%B0%A9%EC%95%88\" aria-label=\"해결 방안 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>해결 방안</h2>\n<ul>\n<li>item의 개수가 20개 이상일 때에만 swipe indicator를 보여주기 위한 filtering을 한다.</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token function\">ngAfterViewInit</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>_sub<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>\n      <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>result$<span class=\"token punctuation\">.</span><span class=\"token function\">pipe</span><span class=\"token punctuation\">(</span>\n        <span class=\"token function\">tap</span><span class=\"token punctuation\">(</span>result <span class=\"token operator\">=></span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>result <span class=\"token operator\">=</span> result<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> result <span class=\"token operator\">&amp;&amp;</span> result<span class=\"token punctuation\">.</span>total <span class=\"token operator\">></span> result<span class=\"token punctuation\">.</span>listNum<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token function\">switchMap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">swipeToSeeMore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<ul>\n<li><code class=\"language-text\">touchmove</code> event를 감지해서 스크롤이 끝에 도달할 경우 이벤트를 전파한다. </li>\n<li>끝에 도달할 경우, touchStartX시점에서 touchmove의 이동량을 계산하여 xDiff(스크롤 이동량)을 계산한다.</li>\n<li>디바이스 화면의 40%만큼 스크롤된 값 즉, xThreshold을 저장한다.(40%의 수치를 100%로 환산) => 40%이상 스크롤될 때 원하는 다음 동작을 실행</li>\n<li>스크롤된 값에서 xThreshold값을 나누어 percentage값을 저장</li>\n<li>40%이상의 스크롤 이후 <code class=\"language-text\">touchend</code> 이벤트가 발생하면 원하는 주소로 이동한다.</li>\n<li>40%이하의 스크롤 이후 <code class=\"language-text\">touchend</code>이벤트가 발생하면 <code class=\"language-text\">translateX</code>값 및 <code class=\"language-text\">strokeDasharray</code> 값을 초기화한다.</li>\n</ul>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token keyword\">private</span> <span class=\"token function\">swipeToSeeMore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> element <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>elementRef<span class=\"token punctuation\">.</span>nativeElement<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> circle <span class=\"token operator\">=</span> <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>circle<span class=\"token punctuation\">.</span>nativeElement<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">let</span> reqId<span class=\"token punctuation\">,</span> percentage<span class=\"token punctuation\">,</span> touchStartX<span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">return</span> <span class=\"token function\">combineLatest</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n      <span class=\"token function\">fromEvent</span><span class=\"token punctuation\">(</span>element<span class=\"token punctuation\">,</span> <span class=\"token string\">'touchmove'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> passive<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">pipe</span><span class=\"token punctuation\">(</span>\n        <span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> scrollWidth<span class=\"token punctuation\">,</span> scrollLeft<span class=\"token punctuation\">,</span> clientWidth <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> element<span class=\"token punctuation\">;</span>\n          <span class=\"token keyword\">return</span> scrollWidth <span class=\"token operator\">-</span> scrollLeft <span class=\"token operator\">-</span> clientWidth <span class=\"token operator\">&lt;=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>touchMove<span class=\"token operator\">:</span> TouchEvent<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> touchMove<span class=\"token punctuation\">.</span>changedTouches<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>clientX<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token function\">tap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>x<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> touchStartX <span class=\"token operator\">=</span> touchStartX <span class=\"token operator\">||</span> x<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token function\">tap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>x<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token comment\">// 디바이스 가로폭 40%까지만 swipe 하면 100%</span>\n          <span class=\"token keyword\">const</span> xThreshold <span class=\"token operator\">=</span> element<span class=\"token punctuation\">.</span>clientWidth <span class=\"token operator\">*</span> <span class=\"token number\">0.4</span><span class=\"token punctuation\">;</span>\n          <span class=\"token keyword\">const</span> xDiff <span class=\"token operator\">=</span> touchStartX <span class=\"token operator\">-</span> x<span class=\"token punctuation\">;</span>\n          percentage <span class=\"token operator\">=</span> Math<span class=\"token punctuation\">.</span><span class=\"token function\">min</span><span class=\"token punctuation\">(</span>xDiff<span class=\"token punctuation\">,</span> xThreshold<span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> xThreshold<span class=\"token punctuation\">;</span>\n          reqId <span class=\"token operator\">=</span> <span class=\"token function\">cancelAndRequestAnimationFrame</span><span class=\"token punctuation\">(</span>reqId<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n\t\t\t\t\t\t<span class=\"token comment\">// transform을 이용해 안드로이드 디바이스에서도 스와이핑이 되게 구현</span>\n            element<span class=\"token punctuation\">.</span>style<span class=\"token punctuation\">.</span>transform <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">translateX(-</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>xDiff <span class=\"token operator\">/</span> <span class=\"token number\">2</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">px)</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n            circle<span class=\"token punctuation\">.</span>style<span class=\"token punctuation\">.</span>strokeDasharray <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>Math<span class=\"token punctuation\">.</span><span class=\"token function\">round</span><span class=\"token punctuation\">(</span>percentage <span class=\"token operator\">*</span> <span class=\"token number\">100</span><span class=\"token punctuation\">)</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">, 100</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n      <span class=\"token function\">fromEvent</span><span class=\"token punctuation\">(</span>element<span class=\"token punctuation\">,</span> <span class=\"token string\">'touchend'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> passive<span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">pipe</span><span class=\"token punctuation\">(</span>\n        <span class=\"token function\">tap</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n          <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>percentage <span class=\"token operator\">>=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>router<span class=\"token punctuation\">.</span><span class=\"token function\">navigate</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>navigateUrl<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n            reqId <span class=\"token operator\">=</span> <span class=\"token function\">cancelAndRequestAnimationFrame</span><span class=\"token punctuation\">(</span>reqId<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n              element<span class=\"token punctuation\">.</span>style<span class=\"token punctuation\">.</span>transform <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">translateX(0px)</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n              circle<span class=\"token punctuation\">.</span>style<span class=\"token punctuation\">.</span>strokeDasharray <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">0, 100</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token punctuation\">}</span>\n          touchStartX <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>이 밖에도 <code class=\"language-text\">strokeDasharray</code>, <code class=\"language-text\">requestAnimationFrame</code> 등 이 기능을 구현 및 최적화하기 위해 알아야할 지식들이 있다. 참고할 문서들이 많으니 링크로 남겨 놓겠다.</p>\n<h4 id=\"결과-화면\" style=\"position:relative;\"><a href=\"#%EA%B2%B0%EA%B3%BC-%ED%99%94%EB%A9%B4\" aria-label=\"결과 화면 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>결과 화면</h4>\n<video width=\"600\" controls>\n  <source src=\"/0d3298cd15dfde951eb8e5bb37513b7c/swipe.mov\" type=\"video/mp4\">\n</video>\n<blockquote>\n<h3 id=\"참고-및-출처\" style=\"position:relative;\"><a href=\"#%EC%B0%B8%EA%B3%A0-%EB%B0%8F-%EC%B6%9C%EC%B2%98\" aria-label=\"참고 및 출처 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>참고 및 출처</h3>\n<ul>\n<li><a href=\"https://stackoverflow.com/questions/2264072/detect-a-finger-swipe-through-javascript-on-the-iphone-and-android\">Detect a finger swipe through JavaScript on the iPhone and Android</a></li>\n<li><a href=\"https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray\">stroke-dasharray</a></li>\n<li><a href=\"https://medium.com/@pppped/how-to-code-a-responsive-circular-percentage-chart-with-svg-and-css-3632f8cd7705\">How to code a responsive circular percentage chart with SVG and CSS.</a></li>\n<li><a href=\"https://developer.mozilla.org/ko/docs/Web/API/Window/requestAnimationFrame\">window.requestAnimationFrame()</a></li>\n</ul>\n</blockquote>","frontmatter":{"title":"Mobile Touch Swipe Indicator","date":"June 25, 2020"}}},"pageContext":{"slug":"/Today I Learned/mobile_touch_swipe_indicator/","previous":{"fields":{"slug":"/Today I Learned/full_height_on_mobile_web/"},"frontmatter":{"title":"Full Height On mobile Web","category":"Today I Learned","draft":false}},"next":{"fields":{"slug":"/Today I Learned/Parent_element에_click이_발생할_때_Child_element의_클릭이벤트를_제어하기/"},"frontmatter":{"title":"Parent element에 click이 발생할 때 child element의 클릭이벤트를 제어하기","category":"Today I Learned","draft":false}}}},"staticQueryHashes":["3128451518","96099027"]}